package com.yeskery.nut.bean.condition;

import com.yeskery.nut.annotation.condition.ConditionalOnClass;
import com.yeskery.nut.application.NutApplication;
import com.yeskery.nut.scan.BeanAnnotationScanMetadata;
import com.yeskery.nut.util.ClassUtils;

import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * 类存在条件判断
 * @author sunjay
 * 2023/9/6
 */
public class OnClassCondition implements Condition {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(OnClassCondition.class.getName());

    @Override
    public boolean matches(NutApplication nutApplication, Collection<BeanAnnotationScanMetadata> beanAnnotationScanMetadata, Object conditionalAnnotation) {
        ConditionalOnClass conditionalOnClass = (ConditionalOnClass) conditionalAnnotation;
        boolean result = doMatches(conditionalOnClass.value(), conditionalOnClass.name());
        if (!result && logger.isLoggable(Level.FINEST)) {
            logger.log(Level.FINEST, "Class Condition Not Match, Condition[" + this.getClass().getName()
                    + "], Expect Class Found[class(" + Arrays.stream(conditionalOnClass.value()).map(Class::getName).collect(Collectors.joining(", "))
                    + "), name(" + String.join(", ", conditionalOnClass.name()) + ")], Actual Class Not Found.");
        }
        return result;
    }

    /**
     * 判断bean是否匹配的方法
     * @param classes 类数组
     * @param classNames 类名称数组
     * @return bean是否匹配的方法
     */
    protected boolean doMatches(Class<?>[] classes, String[] classNames) {
        Set<String> classNameSet = new HashSet<>(classes.length + classNames.length);
        for (Class<?> clazz : classes) {
            classNameSet.add(clazz.getName());
        }
        classNameSet.addAll(Arrays.asList(classNames));
        for (String className : classNameSet) {
            if (!ClassUtils.isExistTargetClass(className)) {
                return false;
            }
        }
        return true;
    }
}
